/*
 * CSnowGenerator.cpp
 *
 *      Author: grifos
 */

#include "CSnowGenerator.h"
#include <iostream>
#include <stdlib.h>
CSnowGenerator::CSnowGenerator(float gravity,int nbMax, float life, float size, float width, float sizeCoef) {
	_gravity = gravity;
	_maxParticle = nbMax;
	_life = life;
	_nbSecond = nbMax/life;
	_particles = new Particle[nbMax];
	_size = size;
	_sizeCoef = sizeCoef;
	_spawnWidth = width;
	_first = 0;
	 srand ( time(NULL) );

	 _snowStateSet = new osg::StateSet;
	 _particleMesh = createParticle();

	 for(int i=0; i < _maxParticle; i++)
	 {
		 _particles[i].lifeSpan = _life;
		 _particles[i].currentLife = _life;
	 }

	 _particlesPos = new osg::ref_ptr<osg::PositionAttitudeTransform>[nbMax];
	 _particlesRot = new osg::ref_ptr<osg::MatrixTransform>[nbMax];
	 for(int i=0; i < nbMax;i++)
	 {
		 _particlesPos[i] = new osg::PositionAttitudeTransform;
		 _particlesRot[i] = new osg::MatrixTransform;
		 _particlesPos[i]->addChild(_particlesRot[i].get());
	 }

	_root = new osg::Group();

	_snowTexture = new osg::Texture2D;
	_snowTexture->setImage(osgDB::readImageFile("./ressource/snowflake.png"));

	osg::AlphaFunc* alphaFunc = new osg::AlphaFunc;
	alphaFunc->setFunction(osg::AlphaFunc::GEQUAL,0.05f);

	_snowStateSet->setMode( GL_LIGHTING, osg::StateAttribute::OFF );
	_snowStateSet->setTextureAttributeAndModes
		  (0, _snowTexture, osg::StateAttribute::ON );
	_snowStateSet->setAttributeAndModes
		  (new osg::BlendFunc, osg::StateAttribute::ON );
	osg::AlphaFunc* alphaFunction = new osg::AlphaFunc;
	alphaFunction->setFunction(osg::AlphaFunc::GEQUAL,0.05f);
	_snowStateSet->setAttributeAndModes( alphaFunc, osg::StateAttribute::ON );

	_particleMesh = createParticle();
	_particleMesh->setDataVariance(osg::Object::DYNAMIC);

	for(int i =0; i< nbMax;i++)
	{
		_root->addChild(_particlesPos[i].get());
		_particlesRot[i]->addChild(_particleMesh.get());
	}

}

CSnowGenerator::~CSnowGenerator() {
	delete[] _particles;
}


void CSnowGenerator::render()
{
	// On render toute les particules
	int i =0;
	for(; i < _maxParticle; i++)
	 {
		osg::Vec3f pos;
		pos.set(_particles[i].pos[0],_particles[i].pos[1],_particles[i].pos[2]);
		_particlesPos[i]->setPosition(pos);
		_particlesRot[i]->preMult(osg::Matrix::rotate( gmtl::Math::deg2Rad( _particles[i].rotSpeed ), _particles[i].rotType[0], _particles[i].rotType[1], _particles[i].rotType[2]));
	 }
}


osg::ref_ptr<osg::Geode> CSnowGenerator::createParticle()
{
	float s = _size / _sizeCoef;

	osg::ref_ptr<osg::Geode> retour = new osg::Geode;
	osg::ref_ptr<osg::Geometry> snowQuad = new osg::Geometry;
	retour->addDrawable(snowQuad.get());


	osg::ref_ptr<osg::Vec3Array> snowVerts = new osg::Vec3Array(4);
	(*snowVerts)[0] = osg::Vec3(-s/2.0f, 0, 0);
	(*snowVerts)[1] = osg::Vec3( s/2.0f, 0, 0);
	(*snowVerts)[2] = osg::Vec3( s/2.0f, s, 0);
	(*snowVerts)[3] = osg::Vec3(-s/2.0f, s, 0);

	snowQuad->setVertexArray(snowVerts.get());

	osg::ref_ptr<osg::Vec2Array> snowTexCoords = new osg::Vec2Array(4);
	(*snowTexCoords)[0].set(0.0f,0.0f);
	(*snowTexCoords)[1].set(1.0f,0.0f);
	(*snowTexCoords)[2].set(1.0f,1.0f);
	(*snowTexCoords)[3].set(0.0f,1.0f);
	snowQuad->setTexCoordArray(0,snowTexCoords.get());

	snowQuad->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,4));

	// Need to assign a color to the underlying geometry, otherwise we'll get
	// whatever color is current applied to our geometry.
	// Create a color array, add a single color to use for all the vertices

	osg::ref_ptr<osg::Vec4Array> colorArray = new osg::Vec4Array;
	colorArray->push_back(osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f) ); // white, fully opaque

	// An index array for assigning vertices to colors (based on index in the array)
	osg::TemplateIndexArray
	  <unsigned int, osg::Array::UIntArrayType,4,1> *colorIndexArray;
	colorIndexArray =
	  new osg::TemplateIndexArray<unsigned int, osg::Array::UIntArrayType,4,1>;
	colorIndexArray->push_back(0);

	// Use the index array to associate the first entry in our index array with all
	// of the vertices.
	snowQuad->setColorArray( colorArray.get());

	snowQuad->setStateSet(_snowStateSet);

	return retour;

}

void CSnowGenerator::update(float time, gmtl::Vec3f spawnCenter)
{
	if(_first==0)
	{
		_first=1;
		return;
	}
	// On update chacune des particules et on crée les nouvelles
	float nbParticleToCreate = _nbSecond*time;
	float x,y;
	int nb=0;
	float j = 0;
	int i=0;

	for(; i < _maxParticle;i++)
	{
		_particles[i].currentLife 	+= time;
		_particles[i].pos[1] 		-= _gravity*time;
		_particles[i].rotSpeed 		= (float)(_particles[i].absoluteRotSpeed)*time;

		if(_particles[i].currentLife >= _particles[i].lifeSpan && j<round(nbParticleToCreate))
		{
			j++;
			x=(float)((rand() % (int)(_spawnWidth*_sizeCoef))-(_spawnWidth*_sizeCoef)/2)/_sizeCoef;
			y=(float)((rand() % (int)(_spawnWidth*_sizeCoef))-(_spawnWidth*_sizeCoef)/2)/_sizeCoef;
			_particles[i].currentLife = 0;
			_particles[i].pos[0] = spawnCenter[0]+x;
			_particles[i].pos[1] = spawnCenter[1]+5;
			_particles[i].pos[2] = spawnCenter[2]+ y;
			int mode = rand() % 2;
			switch(mode)
			{
				case 0: _particles[i].rotType[0] = 1.0f;
						_particles[i].rotType[1] = 0.0f;
						_particles[i].rotType[2] = 0.0f;
					break;
				case 1:	_particles[i].rotType[0] = 1.0f;
						_particles[i].rotType[1] = 0.0f;
						_particles[i].rotType[2] = 1.0f;
					break;
				case 2:	_particles[i].rotType[0] = 1.0f;
						_particles[i].rotType[1] = 1.0f;
						_particles[i].rotType[2] = 1.0f;
					break;
			}
			_particles[i].absoluteRotSpeed = rand()%10 + 35;
		}
		if(_particles[i].currentLife < _particles[i].lifeSpan)
		{
			nb++;
		}
	}
	render();
}

void CSnowGenerator::update(float time, gmtl::Vec3f spawnCenter, float speed,int mov)
{
	if(_first==0)
	{
		_first=1;
		return;
	}
	// On update chacune des particules et on crée les nouvelles
	float nbParticleToCreate = _nbSecond*time;
	float x,y;
	int nb=0;
	float j = 0;
	int i=0;

	for(; i < _maxParticle;i++)
	{
		_particles[i].currentLife 	+= time;
		_particles[i].pos[1] 		-= _gravity*time;
		_particles[i].pos[2] 		+= speed*time*mov;
		_particles[i].rotSpeed 		= (float)(_particles[i].absoluteRotSpeed)*time;

		if(_particles[i].currentLife >= _particles[i].lifeSpan && j<round(nbParticleToCreate))
		{
			j++;
			x=(float)((rand() % (int)(_spawnWidth*_sizeCoef))-(_spawnWidth*_sizeCoef)/2)/_sizeCoef;
			y=(float)((rand() % (int)(_spawnWidth*_sizeCoef))-(_spawnWidth*_sizeCoef)/2)/_sizeCoef;
			_particles[i].currentLife = 0;
			_particles[i].pos[0] = spawnCenter[0]+x;
			_particles[i].pos[1] = spawnCenter[1]+5;
			_particles[i].pos[2] = spawnCenter[2]+ y;
			int mode = rand() % 2;
			switch(mode)
			{
				case 0: _particles[i].rotType[0] = 1.0f;
						_particles[i].rotType[1] = 0.0f;
						_particles[i].rotType[2] = 0.0f;
					break;
				case 1:	_particles[i].rotType[0] = 1.0f;
						_particles[i].rotType[1] = 0.0f;
						_particles[i].rotType[2] = 1.0f;
					break;
				case 2:	_particles[i].rotType[0] = 1.0f;
						_particles[i].rotType[1] = 1.0f;
						_particles[i].rotType[2] = 1.0f;
					break;
			}
			_particles[i].absoluteRotSpeed = rand()%10 + 35;
		}
		if(_particles[i].currentLife < _particles[i].lifeSpan)
		{
			nb++;
		}
	}
	render();
}


